<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

/**
 * Test class
 * ทดสอบการทำงานส่วนต่างๆของเว็บ
 *
 * is_string
 * is_bool
 * is_true
 * is_false
 * is_int
 * is_numeric
 * is_float
 * is_double
 * is_array
 * is_object
 * is_null
 *
 * @author Istvan Pusztai
 * @version 1.0.2 $Id: test.php 7 2009-09-29 06:23:41Z Istvan $
 * @copyright Copyright (C) 2010 Istvan Pusztai (twitter.com/istvanp)
 * @package Unittest
 *
 * */
class Test extends Controller {

    var $timings = array();
    var $tests = array();

    /**
     * Constructor function
     *
     * @return void
     * */
    function Test() {
        parent::Controller();

        // Set time marker for the start of the test suite
        $this->benchmark->mark('first');

        log_message('debug', 'Test Controller Initialized');

        // Load the unit test library
        $this->load->library('unit_test');

        // Load syntax highlighting helper
        $this->load->helper('text');

        // Set mode to strict
        $this->unit->use_strict(TRUE);

        // Disable database debugging so we can test all units without stopping
        // at the first SQL error
        $this->db->db_debug = FALSE;

        // Create list of tests
        $this->_map_tests();
    }

    /**
     * ทดสอบ Score model
     * ทดสอบเพิ่ม ลด score
     * @link Score_m::take_score()
     */
    function score_m_model() {
        $this->benchmark->mark('start');

        require_once APPPATH . 'libraries/Admin_controller' . EXT;
        $this->load->module_path('modules');

        $this->load->module('member');
        $userid = 1; //เป็นข้อมูลทดสอบ
        // ทดสอบเพิ่มคะแนน
        $res = $this->member->model->score_m->take_score($userid, '+5', 'unit test plus score', 'score');
        $this->unit->run($res, 'is_int', 'member->model->score_m->take_score($userid,\'+5\',\'unit test plus score\',\'score\'); เพิ่มคะแนน');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบลดคะแนน
        $this->benchmark->mark('start');
        $res = $this->member->model->score_m->take_score($userid, '-5', 'unit test minus score', 'score');
        $this->unit->run($res, 'is_int', 'member->model->score_m->take_score($userid,\'-5\',\'unit test minus score\',\'score\'); ลดคะแนน');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบ เรียกคะแนนมาแสดง
        $this->benchmark->mark('start');
        $res = $this->member->model->score_m->load_score($userid, 'score');
        $this->unit->run($res, 'is_array', 'member->model->score_m->load_score($userid,\'score\'); เรียกคะแนนขึ้นมาแสดง ได้ array');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบว่าเป็นคะแนนของ member จริงๆ
        $this->benchmark->mark('start');
        $this->unit->run($res['score'], 'is_numeric', 'ต้องได้คะแนน ของ member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        // ทดสอบเรียกคะแนน
        $res = $this->member->model->score_m->load_score($userid, 'score');
        $this->unit->run($res, 'is_array', 'member->model->score_m->load_score($userid,\'score\'); เรียก คะแนนของ user');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบว่าได้ คะแนนจริงๆ
        $this->benchmark->mark('start');
        $this->unit->run($res['score'], 'is_numeric', 'ต้องได้คะแนน ของ member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบเรียก log
        $this->benchmark->mark('start');
        $res = $this->member->model->score_m->load_log($userid, 20, 0, "DESC", 'score');
        $this->unit->run($res, 'is_array', 'load_log($userid,20,0,"DESC",\'score\'); ต้องได้ array ของ member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบว่าได้ คะแนนจริงๆ
        $this->benchmark->mark('start');
        $this->unit->run($res['1']['score'], 'is_numeric', 'ต้องได้คะแนน ของ member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        /** ### ### ### ### ### ### ###  karma ### ### ### ### ### ### ###  * */
        // ทดสอบเพิ่มคะแนน
        $res = $this->member->model->score_m->take_score($userid, '+5', 'unit test plus karma', 'karma');
        $this->unit->run($res, 'is_int', 'member->model->score_m->take_score($userid,\'+5\',\'unit test plus karma\',\'karma\'); เพิ่มคะแนน');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบลดคะแนน
        $this->benchmark->mark('start');
        $res = $this->member->model->score_m->take_score($userid, '-5', 'unit test minus karma', 'karma');
        $this->unit->run($res, 'is_int', 'member->model->score_m->take_score($userid,\'-5\',\'unit test minus karma\',\'karma\'); ลดคะแนน');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบ เรียกคะแนนมาแสดง
        $this->benchmark->mark('start');
        $res = $this->member->model->score_m->load_score($userid, 'karma');
        $this->unit->run($res, 'is_array', 'member->model->score_m->>load_score($userid,\'karma\'); เรียกคะแนนขึ้นมาแสดง ได้ array');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบว่าเป็นคะแนนของ member จริงๆ
        $this->benchmark->mark('start');
        $this->unit->run($res['score'], 'is_numeric', 'ต้องได้คะแนน ของ member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        // ทดสอบเรียกคะแนน
        $res = $this->member->model->score_m->load_score($userid, 'karma');
        $this->unit->run($res, 'is_array', 'member->model->score_m->load_score($userid,\'karma\'); เรียก คะแนนของ user');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบว่าได้ คะแนนจริงๆ
        $this->benchmark->mark('start');
        $this->unit->run($res['score'], 'is_numeric', 'ต้องได้คะแนน ของ member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบเรียก log
        $this->benchmark->mark('start');
        $res = $this->member->model->score_m->load_log($userid, 20, 0, "DESC", 'karma');
        $this->unit->run($res, 'is_array', 'member->model->score_m->load_log($userid,20,0,"DESC",\'karma\'); ต้องได้ array ของ member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบว่าได้ คะแนนจริงๆ
        $this->benchmark->mark('start');
        $this->unit->run($res['1']['score'], 'is_numeric', 'ต้องได้คะแนน ของ member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');


        //ทดสอบว่า เรียก sum คะแนนสมาชิกได้
        $this->benchmark->mark('start');
        $res = $this->member->model->score_m->load_sum_member_score($type = 'score');
        $this->unit->run($res, 'is_numeric', 'ต้องได้คะนนรวมของ สมาชิกทุกคน');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');
        
    }

    function member_m_model(){
        $this->benchmark->mark('start');

        require_once APPPATH . 'libraries/Admin_controller' . EXT;
        $this->load->module_path('modules');

        $this->load->module('member');

        //get simple member profile
        $res = $this->member->model->member_m->getSimpleAllUser();
        $this->unit->run($res, 'is_array', 'ได้ mysql array member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบสร้าง user ใหม่
        $this->benchmark->mark('start');
        $u['user'] = 'testtestonly';
        $u['pass'] = 'testtestonly';
        $u['mail'] = 'testtestonly@testonly.com';
        $this->load->library('tank_auth');
        $data = $this->tank_auth->create_user(
                                            $u['user'],
                                            $u['mail'],
                                            $u['pass'],
                                            1);

        $this->unit->run($data, 'is_array', 'ทดสอบระบบสมัครสมาชิกใหม่');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');


        //เรียกชื่อ username
        $this->benchmark->mark('start');
        $this->unit->run($data['username'], 'testtestonly', 'ต้องตรงกัน');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบการเรียก user id ด้วย login(user,email)
        $this->benchmark->mark('start');
        $res = $this->member->model->member_m->get_user_by_login($data['username']);
        $this->unit->run(intval($res['1']['id']), 'is_int', 'ทดสอบการเรียก user id ด้วย login(user,email)');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');
        
        //ทดสอบ activate (จำลอง admin activate)
        $this->benchmark->mark('start');
        $result = $this->member->model->member_m->activate_user($res['1']['id']);
        $this->unit->run($result, 'is_true', 'ทดสอบ activate (จำลอง admin activate)');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');

        //ทดสอบ ลบ member
        $this->benchmark->mark('start');
        $res = $this->member->model->member_m->delete_user($res['1']['id']);
        $this->unit->run($res, 'is_true', 'ทดสอบ ลบ member');
        $this->benchmark->mark('end');
        $this->timings[] = $this->benchmark->elapsed_time('start', 'end');
    }

    /**
     * Remap function
     * Maps the requested action to a method and performs the tests.
     * Do not modify/delete this function.
     *
     * @author Istvan Pusztai
     * @return void
     * */
    function _remap() {
        $view_data = array();
        $action = $this->uri->rsegment(2);
        $view_data['headings'] = array("types" => array(), "tests" => array());

        switch (strtolower($action)) {
            case 'index':
                $view_data['msg'] = "Please pick a test suite";
                break;
            case 'all':
                $i = 0;
                foreach ($this->tests as $key => $type) {
                    $view_data['headings']['types'][count($this->timings)] = ucfirst($key);
                    foreach ($type as $key2 => $method) {
                        $view_data['headings']['tests'][count($this->timings)] = $method;
                        call_user_func(array($this, $method));
                    }
                }
                break;
            case 'models':
            case 'views':
            case 'libraries':
            case 'helpers':
                if (array_key_exists($action, $this->tests) && count($this->tests[$action]) > 0) {
                    foreach ($this->tests[$action] as $method) {
                        $view_data['headings']['tests'][count($this->timings)] = $method;
                        call_user_func(array($this, $method));
                    }
                } else {
                    $view_data['msg'] = "There are no test suites for $action";
                }
                break;
            default:
                if (array_search_recursive($action, $this->tests)) {
                    call_user_func(array($this, $action));
                } else {
                    $view_data['msg'] = "<em>$action</em> is an invalid test suite";
                }
        }

        // Prepare report
        $report = $this->unit->result();

        // Prepare totals
        $view_data['totals']['all'] = count($report);
        $view_data['totals']['failed'] = 0;

        // Count failures
        foreach ($report as $key => $test) {
            if ($test['Result'] == 'Failed') {
                ++$view_data['totals']['failed'];
            }
        }

        // Count passes
        $view_data['totals']['passed'] = $view_data['totals']['all'] - $view_data['totals']['failed'];

        // Calculate the total time taken for the test suite
        $view_data['total_time'] = $this->benchmark->elapsed_time('first', 'end');

        // Other useful data
        $view_data['tests'] = $this->tests;
        $view_data['type'] = $action;
        $view_data['report'] = $report;
        $view_data['timings'] = $this->timings;

        $this->load->view('unit_test', $view_data);
    }

    /**
     * Map Tests
     * Creates a list of tests from the functions defined in this class.
     * Do not modify/delete this function.
     *
     * @author Istvan Pusztai
     * @return void
     * */
    function _map_tests() {
        $methods = get_class_methods($this);
        natsort($methods);

        foreach ($methods as $method) {
            if (strpos($method, '_') !== 0
                    AND $method != __CLASS__
                    AND $method != "CI_Base"
                    AND $method != "Controller"
                    AND $method != "get_instance"
            ) {
                $length = strlen($method);

                if (strripos($method, 'model') === $length - 5) {
                    $this->tests['models'][] = $method;
                } else if (strripos($method, 'view') === $length - 4) {
                    $this->tests['views'][] = $method;
                } else if (strripos($method, 'library') === $length - 7) {
                    $this->tests['libraries'][] = $method;
                } else if (strripos($method, 'helper') === $length - 6) {
                    $this->tests['helpers'][] = $method;
                }
            }
        }

        return $this->tests;
    }

}

/**
 * Array Search (Rescursive)
 * Searches through an array for a value recursively
 * >>> Place this code in a helper if you use it elsewhere <<<
 *
 * @author Istvan Pusztai
 * @since 1.0.2
 * @param string $needle The value to look for
 * @param array $haystack The array to search
 * @param bool $strict Use strict comparison
 * @return bool
 * */
function array_search_recursive($needle, $haystack, $strict = FALSE, $path = array()) {
    if (!is_array($haystack)) {
        return FALSE;
    }

    foreach ($haystack as $key => $val) {
        if (is_array($val) && $subPath = array_search_recursive($needle, $val, $strict, $path)) {
            $path = array_merge($path, array($key), $subPath);
            return $path;
        } else if ((!$strict && $val == $needle) || ($strict && $val === $needle)) {
            $path[] = $key;
            return $path;
        }
    }

    return FALSE;
}

/* End of file test.php */